package org.icosagon.utils;

import java.util.Vector;

/**
 * Like a Map but completly opposite. Instead of have one key and possibly multiple
 * values there are possibly multiple keys and multiple values. This is pretty much
 * just to objects with different character levels. This does not allow exact
 * copies of an <code>Entry</code>.
 * @author Daniel Owens
 */
public class NumberMap<T> {
    Vector<Entry> entries = new Vector<Entry>();

    public int size() {
        return entries.size();
    }

    public boolean isEmpty() {
        return entries.isEmpty();
    }

    /**
     * Returns true on the first occurrence of the specified key.
     * @param key To be found.
     * @return True if found. False if not.
     */
    public boolean containsKey(Integer key) {
        for(Entry entry : this.entries)
            if(key.equals(entry.getKey()))
                return true;
        return false;
    }
    
    public boolean containsValue(T value) {
        for(Entry entry : this.entries)
            if(value.equals(entry.getValue()))
                return true;
        return false;
    }

    /**
     * Returns the specified <code>Object</code> at every designated character level.
     * @param key
     * @return
     */
    public Vector<T> get(Integer key) {
        Vector<T> store = new Vector<T>();
        for(Entry entry : this.entries)
            if(entry.getKey().equals(key))
                store.add(entry.getValue());
        return store;
    }
    
    public T getAt(int index) {
        return (this.entries.get(index)).getValue();
    }
    
    /**
     * Gets all of the levels that this <code>Object</code> occurs at.
     * @param value
     * @return
     */
    public Vector<Integer> getKeysByValue(T value) {
        Vector<Integer> keys = new Vector<Integer>(3);
        for(Entry entry : this.entries)
            if(entry.getValue().equals(value))
                keys.add(entry.getKey());
        return keys;
    }

    public void put(Integer key, T value) {
        Entry temp = new Entry(key, value);
        for(Entry entry : this.entries) {
            if(entry.equals(temp)) {
                temp = null; //cleanup
                return;
            }
        }
        this.entries.add(temp);
        temp = null; //cleanup
    }

    /**
     * Removes all of the values associated with the selected level.
     * @param key
     * @return null.
     */
    public void remove(Integer key) {
        for(Entry entry : this.entries)
            if(entry.getKey().equals(key))
                this.entries.remove(entry);
    }
    
    public void remove(int key) {
        for(Entry entry : this.entries)
            if(entry.getKey().equals(key))
                this.entries.remove(entry);
    }
    
    public void removeAt(int index) {
        this.entries.remove(index);
    }

    public void clear() {
        this.entries.clear();
    }

    public Vector<Integer> getKeys() {
        Vector<Integer> store = new Vector<Integer>(5);
        for(Entry entry : this.entries) {
            Integer key = entry.getKey();
            if(store.contains(key))
                continue;
            else
                store.add(key);
        }
        return store;
    }
    
    public Vector<T> getValues() {
        Vector<T> store = new Vector<T>();
        for(Entry entry : this.entries)
            store.add(entry.getValue());
        return store;
    }
    
    private class Entry {
        private Integer key;
        private T value;
        
        public Entry(){}
        
        public Entry(Integer key, T value) {
            this.key = key;
            this.value = value;
        }

        public Integer getKey() {
            return this.key;
        }

        public T getValue() {
            return this.value;
        }

        public T setValue(Object value) {
            this.value = (T)value;
            return this.value;
        }
    }
}